#include "index.h"
#include "index_private.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>


static index_attr_node *
index_attr_node_alloc(index_t *index, index_attr *attr)
{
    void *attr_node = NULL;
    assert(attr->attr_node_count < index->max_elem);
    attr_node = (void *) &attr->attr_node_pool[attr->attr_node_count];
    attr_node += attr->attr_node_count * attr->size;
    attr->attr_node_count++;
    memset(attr_node, 0, sizeof(index_attr_node) + attr->size);
    return attr_node;
}

static index_attr_list_node *
index_attr_list_node_alloc(index_t *index, index_attr *attr)
{
    index_attr_list_node *attr_list_node;
    assert(attr->attr_list_node_count < index->max_elem);
    attr_list_node = &attr->attr_list_node_pool[attr->attr_list_node_count++];
    memset(attr_list_node, 0, sizeof(index_attr_list_node));
    return attr_list_node;
}

static void
index_attr_node_free(void *attr_node)
{


}

static int 
index_attr_node_comp(void *a, void *b, void *ctx)
{
    index_attr *attr   = (index_attr *) ctx;
    index_attr_node *A = (index_attr_node *)a;
    index_attr_node *B = (index_attr_node *)b;
    return memcmp(A->data, B->data, attr->size);
}

static void 
index_attr_insert(index_t *index, index_attr *attr, void *item)
{
    index_attr_node      *temp;
    index_attr_node      *search, *attr_node;
    index_attr_list_node *attr_list_node;

    assert(attr->tree != NULL);

    temp = attr->attr_node_temp;

    memcpy(temp->data, item + attr->offset, attr->size);

    search = (index_attr_node *) avl_lookup(attr->tree, temp, attr);

    if (search == NULL) {
        attr_node = index_attr_node_alloc(index, attr);
        memcpy(attr_node->data, item + attr->offset, attr->size);
        avl_insert(attr->tree, attr_node, attr);
        search = attr_node;
    } 

    attr_list_node = index_attr_list_node_alloc(index, attr);
    attr_list_node->item = item;
    list_append(&search->list, (list_node *) attr_list_node);

}


index_t *
index_new(int max_elem, 
          int max_attr, 
          avl_compare_fn comp_fn, 
          avl_free_fn free_fn, 
          int opts) 
{
    index_t *index;

    index = malloc(sizeof(index_t));
    if (index == NULL) return NULL;

    index->attr_count = 0;
    index->max_attr = max_attr;
    index->max_elem = max_elem;

    index->attributes = calloc(max_attr, sizeof(index_attr));
    if (index->attributes == NULL) return NULL;

    if (comp_fn != NULL) {
        index->database = avl_new(comp_fn, free_fn, opts);
        if (index->database == NULL) return NULL;
    }

    return index;
}


void
index_create_attribute(index_t *index, size_t offset, size_t len) 
{
    index_attr *attr;

    assert(index->attr_count < index->max_attr);

    attr = &index->attributes[index->attr_count++];
    attr->offset = offset;
    attr->size = len;
    attr->tree = avl_new(index_attr_node_comp, 
                         index_attr_node_free, 
                         AVL_TREE_INTRUSIVE);

    attr->attr_node_temp = calloc(1, sizeof(index_attr_node) + len);
    attr->attr_node_pool = calloc(index->max_elem, sizeof(index_attr_node) + len);
    attr->attr_list_node_pool = calloc(index->max_elem, sizeof(index_attr_list_node));

}

void
index_insert(index_t *index, void *item, void *ctx)
{
    int              i;
    index_attr      *attr;
    avl_node        *search = NULL;

    assert(index != NULL);

    if (index->database != NULL) {
        search = avl_lookup(index->database, item, ctx);
        if (search != NULL) return;
        avl_insert(index->database, item, ctx);
    }
      
    for (i = 0; i < index->attr_count; i++)  {
        attr = &index->attributes[i];
        index_attr_insert(index, attr, item);
    }
}
    

